
/*
  Author:
  Lu Yiming <lu.yiming.lu@gmail.com>
 */

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <time.h>
#include <math.h>

#include "usage.h"
#include "shm_sysv.h"
#include "shm_sysv2.h"
#include "data.h"


void shm_sysv2_server(int argc, char **argv)
{
	unsigned int i;
	void *buf_recv;
	int old_argc = argc;
	int semid;
	int msgid;
	int debug = 0;

	while (argc > 0) {
		/* for future  
		if ((argc > 1) &&
		    (0 == strcmp(argv[0], "port"))) {
			port = atoi(argv[1]);
			if (!port) {
				fprintf(stderr, "port can't be 0\n");
				exit(EXIT_FAILURE);
			}
			argc -= 2;
			argv += 2;
		}
		*/

		if ((argc > 0) &&
		    (0 == strcmp(argv[0], "debug"))) {
			debug = 1;
			argc -= 1;
			argv += 1;
		}

		if (old_argc == argc) {
			usage();
			exit (EXIT_FAILURE);
		}
		old_argc = argc;
	}

	shm_sysv_init(&buf_recv, &semid, &msgid);

	memset(buf_recv, 0, 1024);
     
	printf("share memory (SYS V) server 2 started\n");

	while(1) {
		/* wait for client data ready and mark */
		while (0 == *((unsigned int*)buf_recv));

		if (debug) {
			fprintf (stderr, "Server: got data, ID: %ld\n", *((unsigned long int *)buf_recv));
		}

		if (*(((unsigned int *)buf_recv + 3)) & (1 << 31)) {
			/* bit 31 means full-deplex */
			for (i = 0; i < 1024 - 12 - 4; i++) {  /* FIXME: loop count should be get from buf_recv */
				((char*)buf_recv)[12 + 4 + i] = 0xA5;
			}
		}

		*((unsigned int*)buf_recv) = 0;
	}
}

void shm_sysv2_client (int argc, char **argv)
{
	unsigned long int i;
	void *buf_send;
	time_t time_start;
	time_t time_end;
	unsigned long int packets = 128 * 1024;
	char duplex = 2;
	int old_argc = argc;
	int semid;
	int msgid;
	int recv;
	int sent;
	unsigned int j;

	while (argc > 0) {
		if ((argc > 1) &&
		    (0 == strcmp(argv[0], "packets"))) {
			packets = atoll(argv[1]);
			argc -= 2;
			argv += 2;
		}
		if ((argc > 0) &&
		    (0 == strcmp(argv[0], "full-duplex"))) {
			duplex = 2;
			argc -= 1;
			argv += 1;
		}
		if ((argc > 0) &&
		    (0 == strcmp(argv[0], "half-duplex"))) {
			duplex = 1;
			argc -= 1;
			argv += 1;
		}
		if (old_argc == argc) {
			usage();
			exit (EXIT_FAILURE);
		}
		old_argc = argc;
	}

	shm_sysv_init(&buf_send, &semid, &msgid);

	time(&time_start);

	for (i = 0; i < packets; i++) {

		/* buf[0-3] = server/client flag */
		while (0 != *((unsigned int *)buf_send));

		/* buf[4-11] = ID, 0...n */
		*((unsigned long int *)((unsigned int *)buf_send + 1)) = i;
		/* buf[12-15] = message size */
		*(((unsigned int *)buf_send + 3)) = (1024 - 12 - 4) | 
		                                    ((1 == duplex) ? 0 : 1 << 31); /* bit 31 means full-deplex */


		if (2 == duplex) {
			for (j = 0; j < 1024 - 12 - 4; j++) {
				((char*)buf_send)[12 + 4 + j] = 0x5A;
			}

			if (*((unsigned long int *)((unsigned int *)buf_send + 1)) != i) {
				perror ("recv ID");
			}
			if ((*(((unsigned int *)buf_send) + 3) & 0xffffff) != (1024 - 12 - 4)) {
				perror ("recv message size");
			}
		}

		*((unsigned int *)buf_send) = 1;
	}
     
	time(&time_end);

	fprintf (stderr, 
		 "Client: done. \n"
		 "Time elapsed (seconds): %'.2f\n"
		 "Packet (1KB) sent%s: %ld\n"
		 "Speed: %'.2f MBps\n"
		 , difftime(time_end, time_start)
		 , (1 == duplex) ? " (half-duplex)" : " and received (full-duplex)"
		 , packets
		 , 1.0 * packets * duplex / 1024 / ((0.0 == difftime(time_end, time_start)) ? 1.0 : difftime(time_end, time_start)));
     
}
